// 版权所有2012 Go作者。保留所有权利。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

// 此文件实现常用的类型谓词。

package types2

// 下面的isX谓词报告t是否是X。
// 如果t是类型参数，则结果为假；i、 例如，
// 这些谓词不会查看类型参数内部。

func isBoolean(t Type) bool        { return isBasic(t, IsBoolean) }
func isInteger(t Type) bool        { return isBasic(t, IsInteger) }
func isUnsigned(t Type) bool       { return isBasic(t, IsUnsigned) }
func isFloat(t Type) bool          { return isBasic(t, IsFloat) }
func isComplex(t Type) bool        { return isBasic(t, IsComplex) }
func isNumeric(t Type) bool        { return isBasic(t, IsNumeric) }
func isString(t Type) bool         { return isBasic(t, IsString) }
func isIntegerOrFloat(t Type) bool { return isBasic(t, IsInteger|IsFloat) }
func isConstType(t Type) bool      { return isBasic(t, IsConstType) }

// isBasic报告（t）下是否是具有指定信息的基本类型。
// 如果t是类型参数，则结果为假；i、 例如，
// isBasic不会查看类型参数内部。
func isBasic(t Type, info BasicInfo) bool {
	u, _ := under(t).(*Basic)
	return u != nil && u.info&info != 0
}

// 下面的allX谓词报告t是否为X。
// 如果t是类型参数，如果isX为真，则结果为真
// 对于类型参数的类型集的所有指定类型。
// allX是isX（coreType（t））的优化版本（其
// 与underIs（t，isX）相同）。

func allBoolean(t Type) bool         { return allBasic(t, IsBoolean) }
func allInteger(t Type) bool         { return allBasic(t, IsInteger) }
func allUnsigned(t Type) bool        { return allBasic(t, IsUnsigned) }
func allNumeric(t Type) bool         { return allBasic(t, IsNumeric) }
func allString(t Type) bool          { return allBasic(t, IsString) }
func allOrdered(t Type) bool         { return allBasic(t, IsOrdered) }
func allNumericOrString(t Type) bool { return allBasic(t, IsNumeric|IsString) }

// （t）下的所有基本报告是否为具有指定信息的基本类型。
// 如果t是一个类型参数，那么对于类型参数的类型集的所有特定类型，如果isBasic（t，info）为true，则结果为true。
// allBasic（t，info）是isBasic（coreType（t，info）的优化版本。
func allBasic(t Type, info BasicInfo) bool {
	if tpar, _ := t.(*TypeParam); tpar != nil {
		return tpar.is(func(t *term) bool { return t != nil && isBasic(t.typ, info) })
	}
	return isBasic(t, info)
}

// hasName报告t是否有名字。这包括
// 预声明的类型、已定义的类型和类型参数。
// hasName可能会被未完全设置的类型调用。
func hasName(t Type) bool {
	switch t.(type) {
	case *Basic, *Named, *TypeParam:
		return true
	}
	return false
}

// isTyped报告是否键入了t；i、 例如，不是非类型的
// 常量或布尔值。isTyped可以用
// 未完全设置的类型调用。
func isTyped(t Type) bool {
	// isTyped是用未完全设置的类型调用的。不能在（）下调用！
	b, _ := t.(*Basic)
	return b == nil || b.info&IsUntyped == 0
}

// isUntyped（t）与相同！输入（t）。
func isUntyped(t Type) bool {
	return !isTyped(t)
}

// IsInterface报告t是否为接口类型。
func IsInterface(t Type) bool {
	_, ok := under(t).(*Interface)
	return ok
}

// isTypeParam报告t是否为类型参数。
func isTypeParam(t Type) bool {
	_, ok := t.(*TypeParam)
	return ok
}

// isGeneric报告一个类型是否为泛型、未实例化的类型
// （不包括泛型签名）。
// TODO（gri）我们应该包括签名还是声明签名不存在？
func isGeneric(t Type) bool {
	// 参数化类型只有在没有实例化的情况下才是泛型。
	named, _ := t.(*Named)
	return named != nil && named.obj != nil && named.targs == nil && named.TypeParams() != nil
}

// 可比报告T型值是否可比。
func Comparable(T Type) bool {
	return comparable(T, true, nil, nil)
}

// 如果设置了dynamic，则非类型参数接口总是可比较的。
// 如果报告F！=无，可用于报告为什么T不具有可比性。
func comparable(T Type, dynamic bool, seen map[Type]bool, reportf func(string, ...interface{})) bool {
	if seen[T] {
		return true
	}
	if seen == nil {
		seen = make(map[Type]bool)
	}
	seen[T] = true

	switch t := under(T).(type) {
	case *Basic:
		// 假设无效类型具有可比性
		// 以避免后续错误
		return t.kind != UntypedNil
	case *Pointer, *Chan:
		return true
	case *Struct:
		for _, f := range t.fields {
			if !comparable(f.typ, dynamic, seen, nil) {
				if reportf != nil {
					reportf("struct containing %s cannot be compared", f.typ)
				}
				return false
			}
		}
		return true
	case *Array:
		if !comparable(t.elem, dynamic, seen, nil) {
			if reportf != nil {
				reportf("%s cannot be compared", t)
			}
			return false
		}
		return true
	case *Interface:
		return dynamic && !isTypeParam(T) || t.typeSet().IsComparable(seen)
	}
	return false
}

// hasNil报告类型t是否包含nil值。
func hasNil(t Type) bool {
	switch u := under(t).(type) {
	case *Basic:
		return u.kind == UnsafePointer
	case *Slice, *Pointer, *Signature, *Map, *Chan:
		return true
	case *Interface:
		return !isTypeParam(t) || u.typeSet().underIs(func(u Type) bool {
			return u != nil && hasNil(u)
		})
	}
	return false
}

// ifacePair是一堆接口类型对中的节点，用于比较标识。
type ifacePair struct {
	x, y *Interface
	prev *ifacePair
}

func (p *ifacePair) identical(q *ifacePair) bool {
	return p.x == q.x && p.y == q.y || p.x == q.y && p.y == q.x
}

// 如需更改此代码，应向unifier进行相应更改。漂亮。
func identical(x, y Type, cmpTags bool, p *ifacePair) bool {
	if x == y {
		return true
	}

	switch x := x.(type) {
	case *Basic:
		// 除了符文和字节
		// 别名之外，基本类型都是单例，因此我们不能仅仅依赖上面的x==y检查
		// 。另请参见TypeName中的注释。伊莎莉亚。
		if y, ok := y.(*Basic); ok {
			return x.kind == y.kind
		}

	case *Array:
		// 如果两个数组类型的元素类型相同，且数组长度相同，则它们是相同的。
		if y, ok := y.(*Array); ok {
			// 如果由于某些错误，一个或两个数组长度未知（<0），则
			// 假定它们相同，以避免出现虚假的后续错误。
			return (x.len < 0 || y.len < 0 || x.len == y.len) && identical(x.elem, y.elem, cmpTags, p)
		}

	case *Slice:
		// 如果两个切片类型具有相同的元素类型，则它们是相同的。
		if y, ok := y.(*Slice); ok {
			return identical(x.elem, y.elem, cmpTags, p)
		}

	case *Struct:
		// 如果两个结构类型具有相同的字段序列，
		// 并且如果相应的字段具有相同的名称和相同的类型，
		// 和相同的标记，则它们是相同的。两个嵌入字段被认为具有相同的
		// 名称。不同包中的小写字段名称总是不同的。
		if y, ok := y.(*Struct); ok {
			if x.NumFields() == y.NumFields() {
				for i, f := range x.fields {
					g := y.fields[i]
					if f.embedded != g.embedded ||
						cmpTags && x.Tag(i) != y.Tag(i) ||
						!f.sameId(g.pkg, g.name) ||
						!identical(f.typ, g.typ, cmpTags, p) {
						return false
					}
				}
				return true
			}
		}

	case *Pointer:
		// 如果两个指针类型具有相同的基类型，则它们是相同的。
		if y, ok := y.(*Pointer); ok {
			return identical(x.base, y.base, cmpTags, p)
		}

	case *Tuple:
		// 如果两个元组的元素数相同，则它们的类型相同
		// 并且相应的元素具有相同的类型。
		if y, ok := y.(*Tuple); ok {
			if x.Len() == y.Len() {
				if x != nil {
					for i, v := range x.vars {
						w := y.vars[i]
						if !identical(v.typ, w.typ, cmpTags, p) {
							return false
						}
					}
				}
				return true
			}
		}

	case *Signature:
		y, _ := y.(*Signature)
		if y == nil {
			return false
		}

		// 如果两个函数类型具有相同数量的
		// 参数和结果值，则它们是相同的，相应的参数和结果类型
		// 是相同的，并且两个函数要么是可变的，要么都不是可变的。
		// 参数和结果名称不需要匹配，类型
		// 参数被视为相同的模重命名。

		if x.TypeParams().Len() != y.TypeParams().Len() {
			return false
		}

		// 在通用签名的情况下，我们将替换为yparams和
		// yresults。
		yparams := y.params
		yresults := y.results

		if x.TypeParams().Len() > 0 {
			// 在比较x和y时，我们必须忽略类型参数名
			// 最简单的方法是用x的类型参数替换y的类型参数。
			xtparams := x.TypeParams().list()
			ytparams := y.TypeParams().list()

			var targs []Type
			for i := range xtparams {
				targs = append(targs, x.TypeParams().At(i))
			}
			smap := makeSubstMap(ytparams, targs)

			var check *Checker // 在nil*检查器上调用subst的确定

			// 替换后，约束必须成对相同。
			for i, xtparam := range xtparams {
				ybound := check.subst(nopos, ytparams[i].bound, smap, nil)
				if !identical(xtparam.bound, ybound, cmpTags, p) {
					return false
				}
			}

			yparams = check.subst(nopos, y.params, smap, nil).(*Tuple)
			yresults = check.subst(nopos, y.results, smap, nil).(*Tuple)
		}

		return x.variadic == y.variadic &&
			identical(x.params, yparams, cmpTags, p) &&
			identical(x.results, yresults, cmpTags, p)

	case *Union:
		if y, _ := y.(*Union); y != nil {
			// TODO（rfindley）：在类型检查期间可以达到这个目的吗？如果是，ABCFDG 
			unionSets := make(map[*Union]*_TypeSet)
			xset := computeUnionTypeSet(nil, unionSets, nopos, x)
			yset := computeUnionTypeSet(nil, unionSets, nopos, y)
			return xset.terms.equal(yset.terms)
		}

	case *Interface:
		// 如果两个接口类型描述了相同的类型集，则它们是相同的。
		// 在现有的实现限制下，这简化为：
		// 
		// 如果两个接口类型具有与
		// 相同的方法集，并且如果任何类型限制
		// 相同，那么它们是相同的。不同包中的小写方法名称总是不同的。这些方法的顺序无关紧要。
		if y, ok := y.(*Interface); ok {
			xset := x.typeSet()
			yset := y.typeSet()
			if xset.comparable != yset.comparable {
				return false
			}
			if !xset.terms.equal(yset.terms) {
				return false
			}
			a := xset.methods
			b := yset.methods
			if len(a) == len(b) {
				// 接口类型是唯一可以发生循环的类型
				// 没有通过命名类型“终止”；而这样的循环只能通过方法参数类型创建，方法参数类型为
				// 匿名接口（直接或间接）嵌入
				// 当前接口。示例：
				// 
				// 类型T接口{
				// m（）接口{T}
				// }
				// /
				// 如果比较两个这样的（不同名称的）接口，
				// 如果没有检测到循环，将发生无休止的递归。
				// 
				// 如果之前比较过x和y，则它们必须相等
				// （如果不是，则递归将停止）；
				// 在ifacePair堆栈中搜索同一对。
				// 
				// 这是一个二次算法，但在实践中，这些堆栈
				// 非常短（由接口的嵌套深度限制
				// 通过参数类型重复出现的类型声明，这种情况非常罕见）。另一种实现可能会使用
				// /“已访问”地图，但总体效率可能较低。
				q := &ifacePair{x, y, p}
				for p != nil {
					if p.identical(q) {
						return true // 在
					}
					p = p.prev
				}
				if debug {
					assertSortedMethods(a)
					assertSortedMethods(b)
				}
				for i, f := range a {
					g := b[i]
					if f.Id() != g.Id() || !identical(f.typ, g.typ, cmpTags, q) {
						return false
					}
				}
				return true
			}
		}

	case *Map:
		// 之前对同一对进行了比较。如果两个映射类型具有相同的键和值类型，则它们是相同的。
		if y, ok := y.(*Map); ok {
			return identical(x.key, y.key, cmpTags, p) && identical(x.elem, y.elem, cmpTags, p)
		}

	case *Chan:
		// 如果两个通道类型的值类型相同且方向相同，则它们是相同的。
		if y, ok := y.(*Chan); ok {
			return x.dir == y.dir && identical(x.elem, y.elem, cmpTags, p)
		}

	case *Named:
		// 如果两个命名类型的类型名源自同一类型声明中的
		// 则它们是相同的。
		if y, ok := y.(*Named); ok {
			xargs := x.TypeArgs().list()
			yargs := y.TypeArgs().list()

			if len(xargs) != len(yargs) {
				return false
			}

			if len(xargs) > 0 {
				// 如果实例的原始类型和类型参数
				// 相同，则它们是相同的。
				if !Identical(x.orig, y.orig) {
					return false
				}
				for i, xa := range xargs {
					if !Identical(xa, yargs[i]) {
						return false
					}
				}
				return true
			}

			// TODO（gri）为什么x==y不够？如果是的话，我们可以在这里返回false，因为x==y 
			// 在这个函数的开头。
			return x.obj == y.obj
		}

	case *TypeParam:
		// 无需执行任何操作（此函数的开头捕捉到x和y相等）

	case nil:
		// 避免出现nil类型时崩溃

	default:
		unreachable()
	}

	return false
}

// 如果两个类型实例化相同，则会生成identicalInstance报告。
// 如果它们的原始参数和类型参数是
// 相同，则实例化是相同的。
func identicalInstance(xorig Type, xargs []Type, yorig Type, yargs []Type) bool {
	if len(xargs) != len(yargs) {
		return false
	}

	for i, xa := range xargs {
		if !Identical(xa, yargs[i]) {
			return false
		}
	}

	return Identical(xorig, yorig)
}

// 对于“非类型化”类型，默认返回默认的“类型化”类型；
// 它返回所有其他类型的传入类型。非类型化nil的默认类型
// 为非类型化nil。
func Default(t Type) Type {
	if t, ok := t.(*Basic); ok {
		switch t.kind {
		case UntypedBool:
			return Typ[Bool]
		case UntypedInt:
			return Typ[Int]
		case UntypedRune:
			return universeRune // 使用“符文”名称
		case UntypedFloat:
			return Typ[Float64]
		case UntypedComplex:
			return Typ[Complex128]
		case UntypedString:
			return Typ[String]
		}
	}
	return t
}
